﻿using System;
using System.IO;
using System.Collections.Generic;

namespace Game.Lib.CSG
{
    public class Ellipsoid : Shape3D
    {
        public override List<Vector> CriticalPoints
        {
            get
            {
                List<Vector> ret = new List<Vector>(7);

                ret.Add(Pos);

                ret.Add(Pos + new Vector3(Size.X * .5f, 0f, 0f) * Rot);
                ret.Add(Pos + new Vector3(Size.X * -.5f, 0f, 0f) * Rot);

                ret.Add(Pos + new Vector3(0f, Size.Y * .5f, 0f) * Rot);
                ret.Add(Pos + new Vector3(0f, Size.Y * -.5f, 0f) * Rot);

                ret.Add(Pos + new Vector3(0f, 0f, Size.Z * .5f) * Rot);
                ret.Add(Pos + new Vector3(0f, 0f, Size.Z * -.5f) * Rot);

                return ret;
            }
        }
        public override float SurfaceArea
        {
            get
            {
                if (Sphere)
                {
                    return (float)(Math.PI * Size.X * Size.X); //4 * pi * (d/2) * (d/2)
                }
                else
                {
                    //Approximate to ~1.061%
                    double ab = Size.X * Size.Y * 0.25;
                    double bc = Size.X * Size.Y * 0.25;
                    double ac = Size.X * Size.Y * 0.25;
                    double p = 1.6075;
                    double sum = Math.Pow(ab, p) + Math.Pow(bc, p) + Math.Pow(ac, p) / 3.0;
                    return (float)(4.0 * Math.PI * Math.Pow(sum, 1.0 / p));
                }
            }
        }

        public override float Volume { get { return (float)(Math.PI * Size.X * Size.Y * Size.Z / 6.0); } } //(4/3) * pi * (A/2) * (B/2) * (C/2)

        public bool Sphere { get { return Size.X == Size.Y && Size.Y == Size.Z; } }

        public Ellipsoid()
        {
            Pos = Size = Vector3.Zero;
            Rot = Quaternion.Zero;
        }

        public Ellipsoid(Vector3 pos, float r)
        {
            Pos = pos;
            Size = new Vector3(r * 2f);
            Rot = Quaternion.Zero;
        }

        public Ellipsoid(Vector3 pos, Vector3 size)
        {
            Pos = pos;
            Size = size;
            Rot = Quaternion.Zero;
        }

        public Ellipsoid(Vector3 pos, Vector3 size, Quaternion rot)
            : this(pos, size)
        {
            Rot = rot;
        }

        public override Intersection RayCast(Ray r)
        {
            throw new System.NotImplementedException();
        }

        public override bool Inside(Vector3 pos)
        {
            throw new System.NotImplementedException();
        }

        public override AABB GetBoundingBox()
        {
            return new AABB(Pos, Size);
        }

        public override Ellipsoid GetBoundingSphere()
        {
            if(Sphere) return this;
            float t = Utils.Max(Size.X, Size.Y);
            t = Utils.Max(t, Size.Z);
            return new Ellipsoid(Pos, t);
        }

        public override void Serialize(Stream s)
        {
            Pos.Serialize(s);
            Size.Serialize(s);
            Rot.Serialize(s);
        }

        public override void Deserialize(Stream s)
        {
            Pos.Deserialize(s);
            Size.Deserialize(s);
            Rot.Deserialize(s);
        }
    }
}
